Skip to content

[CCR] Migrate to TS#260601

Merged
kapral18 merged 35 commits intoelastic:mainfrom
kapral18:chore/ccr/migrate-to-ts-239613
Apr 27, 2026
Merged

[CCR] Migrate to TS#260601
kapral18 merged 35 commits intoelastic:mainfrom
kapral18:chore/ccr/migrate-to-ts-239613

Conversation

@kapral18
Copy link
Copy Markdown
Contributor

@kapral18 kapral18 commented Mar 31, 2026

Closes #239613.

Review tip: this PR is intentionally split into small, focused commits. Reviewing commit-by-commit is recommended; GitHub rename detection may show some .js → .ts moves as delete+add.

Summary

  • Migrates Cross-Cluster Replication UI code and client integration tests from JS/JSX to TS/TSX, including a rename-only foundation commit and removal of legacy .d.ts stubs in the migrated area.
  • Tightens type boundaries across API services, HTTP error handling, routing/utils helpers, Redux actions/reducers/selectors, and key React components/pages to preserve behavior while removing migration-era ambiguity.
  • Includes the minimal non-public/ updates required by the migration chain: CCR common serialization typing alignment, one CCR server route typing/payload alignment, tsconfig/moon metadata updates, and CCR functional/a11y test typing updates.
  • Removes now-redundant PropTypes in typed components and keeps generated/lint follow-up commits isolated for review clarity.

Notable runtime fixes/changes

  • Normalizes API errors through shared CcrApiError helpers so rendering/notification paths handle non-Error throwables safely and extract status/message consistently.
  • Keeps follower-index create/update request payloads aligned with write-shape contracts so response-only fields are not sent in create requests.
  • Hardens follower index default-setting lookup by checking key presence (not value truthiness), avoiding false "unknown setting" failures for future falsy defaults.
  • Validates auto-follow pattern form fields incrementally — only after a value is provided — so untouched fields don't surface "required" errors when an unrelated field is edited or after a failed submit.
  • Splits the auto-follow pattern save thunk into createAutoFollowPattern and updateAutoFollowPattern, so the update path only sends fields the route's unknowns: 'forbid' schema accepts and no longer 400s on extra fields carried on the form/state object.
  • Computes API authorization from error.response?.status ?? error.body?.statusCode, so 403 responses correctly flag the API as unauthorized in selectors that gate UI affordances.
  • Centralizes router access through routing.reactRouterOrThrow (backed by a JS private #reactRouter field), so consumers that try to read the router before it is set get a clear error instead of silently null-derefing inside JSX.
  • Replaces definite-assignment on the CCR notifications service (_toasts / _fatalErrors) with runtime checks that throw 'CCR notifications service has not been initialized', surfacing init order bugs at the access site instead of as a misleading cannot read 'add' of undefined.
  • Makes FormEntryRow's title prop required at the type boundary and drops the title! non-null assertion in JSX, so a caller forgetting to pass title becomes a type error instead of a runtime crash.

Commit structure

  • Rename-only migration scaffold.
  • Incremental typing commits by concern (API/errors/store/forms/pages/home/test helpers).
  • Final mechanical sync commits from project tooling (lint_ts_projects, moon regeneration, eslint) kept separate.

Test plan

  • node scripts/type_check --project x-pack/platform/plugins/private/cross_cluster_replication/tsconfig.json
  • node scripts/jest x-pack/platform/plugins/private/cross_cluster_replication ✅ (36 suites, 213 tests)
  • node scripts/check_changes.ts

Assisted with Cursor

@kapral18 kapral18 added Team:Kibana Management Dev Tools, Index Management, Upgrade Assistant, ILM, Ingest Node Pipelines, and more t// release_note:skip Skip the PR/issue when compiling release notes backport:skip This PR does not require backporting technical debt Improvement of the software architecture and operational architecture v9.4.0 labels Mar 31, 2026
@kapral18
Copy link
Copy Markdown
Contributor Author

@coderabbitai full review
@macroscope review this PR

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 31, 2026

@kapral18 Sure! Kicking off a full review of this CCR TypeScript migration PR now.


🧠 Learnings used
Learnt from: CR
Repo: elastic/kibana PR: 0
File: x-pack/solutions/observability/plugins/observability_agent_builder/AGENTS.md:0-0
Timestamp: 2026-03-06T09:23:07.998Z
Learning: Applies to x-pack/solutions/observability/plugins/observability_agent_builder/server/tools/**/*.{ts,tsx,js} : Follow tool design principles, ECS/OTel compatibility, APM data types, parameter conventions, testing workflows, and pre-merge checklist for Observability tools as documented in server/tools/AGENTS.md

Learnt from: CR
Repo: elastic/kibana PR: 0
File: x-pack/solutions/observability/plugins/observability_agent_builder/AGENTS.md:0-0
Timestamp: 2026-03-18T14:14:05.681Z
Learning: Applies to x-pack/solutions/observability/plugins/observability_agent_builder/server/**/*.{ts,tsx,js} : Follow design principles, ECS/OTel compatibility, APM data types, parameter conventions, and testing workflows as documented in the Development Guide

Learnt from: CR
Repo: elastic/kibana PR: 0
File: x-pack/solutions/observability/plugins/observability_agent_builder/server/AGENTS.md:0-0
Timestamp: 2026-03-18T14:14:27.801Z
Learning: Applies to x-pack/solutions/observability/plugins/observability_agent_builder/server/x-pack/solutions/observability/test/api_integration_deployment_agnostic/apis/observability_agent_builder/tools/**/*.ts : Create API integration tests for new tools covering filters, groupBy dimensions, and edge cases in `x-pack/solutions/observability/test/api_integration_deployment_agnostic/apis/observability_agent_builder/tools/`.

Learnt from: CR
Repo: elastic/kibana PR: 0
File: x-pack/solutions/observability/plugins/observability_agent_builder/AGENTS.md:0-0
Timestamp: 2026-03-06T03:54:46.342Z
Learning: Applies to x-pack/solutions/observability/plugins/observability_agent_builder/x-pack/solutions/observability/test/api_integration_deployment_agnostic/apis/observability_agent_builder/**/*.{ts,tsx,js} : Follow API integration test structure guidelines and use shared utilities as documented in x-pack/solutions/observability/test/api_integration_deployment_agnostic/apis/observability_agent_builder/AGENTS.md

Learnt from: CR
Repo: elastic/kibana PR: 0
File: x-pack/solutions/observability/plugins/observability_agent_builder/AGENTS.md:0-0
Timestamp: 2026-03-18T14:14:05.681Z
Learning: Applies to x-pack/solutions/observability/plugins/observability_agent_builder/x-pack/solutions/observability/test/api_integration_deployment_agnostic/apis/observability_agent_builder/**/*.{ts,tsx,js} : Structure API integration tests following the guidelines in the API Integration Tests guide, using shared utilities and following test structure conventions

Learnt from: CR
Repo: elastic/kibana PR: 0
File: x-pack/solutions/security/test/security_solution_cypress/.cursor/rules/flaky_test_doctor.mdc:0-0
Timestamp: 2026-03-06T00:27:42.746Z
Learning: Applies to x-pack/solutions/security/test/security_solution_cypress/**/*.cy.ts : Before deleting a Cypress test, verify that full duplicate coverage exists at API and/or unit test levels. Document the exact files and test names that provide coverage. If deletion is approved, also clean up orphaned code in tasks/, screens/, and objects/ files that were only used by the deleted test.
✅ Actions performed

Full review triggered.

@macroscopeapp
Copy link
Copy Markdown
Contributor

macroscopeapp Bot commented Mar 31, 2026

Just FYI for future @mentions, I'm Macroscope-App, not Macroscope.

I've completed the review. You can view the results here:

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 1, 2026

@kapral18 On it! Triggering a full review of this CCR TypeScript migration PR.


🧠 Learnings used
Learnt from: CR
Repo: elastic/kibana PR: 0
File: x-pack/solutions/observability/plugins/observability_agent_builder/AGENTS.md:0-0
Timestamp: 2026-03-06T09:23:07.998Z
Learning: Applies to x-pack/solutions/observability/plugins/observability_agent_builder/server/tools/**/*.{ts,tsx,js} : Follow tool design principles, ECS/OTel compatibility, APM data types, parameter conventions, testing workflows, and pre-merge checklist for Observability tools as documented in server/tools/AGENTS.md

Learnt from: CR
Repo: elastic/kibana PR: 0
File: x-pack/solutions/observability/plugins/observability_agent_builder/AGENTS.md:0-0
Timestamp: 2026-03-18T14:14:05.681Z
Learning: Applies to x-pack/solutions/observability/plugins/observability_agent_builder/server/**/*.{ts,tsx,js} : Follow design principles, ECS/OTel compatibility, APM data types, parameter conventions, and testing workflows as documented in the Development Guide

Learnt from: CR
Repo: elastic/kibana PR: 0
File: x-pack/solutions/observability/plugins/observability_agent_builder/AGENTS.md:0-0
Timestamp: 2026-03-06T03:54:46.342Z
Learning: Applies to x-pack/solutions/observability/plugins/observability_agent_builder/x-pack/solutions/observability/test/api_integration_deployment_agnostic/apis/observability_agent_builder/**/*.{ts,tsx,js} : Follow API integration test structure guidelines and use shared utilities as documented in x-pack/solutions/observability/test/api_integration_deployment_agnostic/apis/observability_agent_builder/AGENTS.md

Learnt from: CR
Repo: elastic/kibana PR: 0
File: x-pack/solutions/observability/plugins/observability_agent_builder/server/AGENTS.md:0-0
Timestamp: 2026-03-18T14:14:27.801Z
Learning: Applies to x-pack/solutions/observability/plugins/observability_agent_builder/server/x-pack/solutions/observability/test/api_integration_deployment_agnostic/apis/observability_agent_builder/tools/**/*.ts : Create API integration tests for new tools covering filters, groupBy dimensions, and edge cases in `x-pack/solutions/observability/test/api_integration_deployment_agnostic/apis/observability_agent_builder/tools/`.

Learnt from: CR
Repo: elastic/kibana PR: 0
File: x-pack/solutions/security/test/security_solution_cypress/.cursor/rules/flaky_test_doctor.mdc:0-0
Timestamp: 2026-03-06T00:27:42.746Z
Learning: Applies to x-pack/solutions/security/test/security_solution_cypress/**/*.cy.ts : Before deleting a Cypress test, verify that full duplicate coverage exists at API and/or unit test levels. Document the exact files and test names that provide coverage. If deletion is approved, also clean up orphaned code in tasks/, screens/, and objects/ files that were only used by the deleted test.

Learnt from: CR
Repo: elastic/kibana PR: 0
File: x-pack/solutions/observability/plugins/observability_agent_builder/AGENTS.md:0-0
Timestamp: 2026-03-18T14:14:05.681Z
Learning: Applies to x-pack/solutions/observability/plugins/observability_agent_builder/x-pack/solutions/observability/test/api_integration_deployment_agnostic/apis/observability_agent_builder/**/*.{ts,tsx,js} : Structure API integration tests following the guidelines in the API Integration Tests guide, using shared utilities and following test structure conventions

Learnt from: CR
Repo: elastic/kibana PR: 0
File: x-pack/solutions/observability/plugins/observability_agent_builder/AGENTS.md:0-0
Timestamp: 2026-03-18T14:14:05.681Z
Learning: Applies to x-pack/solutions/observability/plugins/observability_agent_builder/server/routes/ai_insights/**/*.{ts,tsx,js} : Design AI Insights with prefetched context and hardcoded prompts, ensure proper prompt design, UI integration, conversation handoff, and test thoroughly

Learnt from: CR
Repo: elastic/kibana PR: 0
File: x-pack/solutions/security/test/security_solution_cypress/.cursor/rules/flaky_test_doctor.mdc:0-0
Timestamp: 2026-03-06T00:27:42.746Z
Learning: Applies to x-pack/solutions/security/test/security_solution_cypress/**/*.cy.ts : For Cypress tests covering Security Solution features (Detection Engine, Timeline, Cases, Entity Analytics, Asset Management, AI Assistant, Attack Discovery), follow the Flaky Test Doctor analysis framework: verify functionality validity (Step 0), establish environment context (Step 1), check for duplicate coverage (Step 2), analyze testing layer (Step 3), classify bug vs flakiness (Step 4), then propose fixes (Step 5)

Learnt from: CR
Repo: elastic/kibana PR: 0
File: x-pack/solutions/observability/plugins/observability_agent_builder/AGENTS.md:0-0
Timestamp: 2026-03-06T12:00:53.329Z
Learning: Applies to x-pack/solutions/observability/plugins/observability_agent_builder/server/routes/ai_insights/**/*.{ts,tsx,js} : Follow AI Insights architecture guidelines including prefetched context, hardcoded prompts, prompt design, UI integration, conversation handoff, and testing as documented in server/routes/ai_insights/AGENTS.md

Learnt from: CR
Repo: elastic/kibana PR: 0
File: x-pack/solutions/observability/plugins/observability_agent_builder/server/AGENTS.md:0-0
Timestamp: 2026-03-18T14:14:27.801Z
Learning: Applies to x-pack/solutions/observability/plugins/observability_agent_builder/server/src/platform/packages/shared/kbn-synthtrace/src/scenarios/agent_builder/tools/**/*.ts : Create Synthtrace scenarios for test data generation in `src/platform/packages/shared/kbn-synthtrace/src/scenarios/agent_builder/tools/`.
✅ Actions performed

Full review triggered.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 1, 2026

📝 Walkthrough

Walkthrough

This pull request completes a TypeScript migration of the Cross-Cluster Replication plugin codebase. JavaScript files across client-integration tests, fixtures, helpers, components, services, and Redux store management are converted to TypeScript with explicit type annotations. PropTypes-based runtime validation is replaced with TypeScript interfaces for React components. Service modules gain typed function signatures, Redux actions and reducers are reimplemented with full type coverage, and HTTP mocking utilities transition from JavaScript to a typed module. Test helpers introduce structured return types, and mock factories adopt partial parameter patterns to support optional fields.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • 🛠️ Update Documentation: Commit on current branch
  • 🛠️ Update Documentation: Create PR

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (1)
x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/form_entry_row.tsx (1)

143-149: Redundant ternary branch.

Lines 146-148: Array.isArray(error) ? error : error evaluates to error regardless of the condition.

Suggested simplification
           error={
-            (structured && structured.message !== undefined
-              ? structured.message
-              : Array.isArray(error)
-              ? error
-              : error) as ReactNode
+            ((structured?.message !== undefined ? structured.message : error) as ReactNode)
           }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/form_entry_row.tsx`
around lines 143 - 149, The ternary in the error prop inside FormEntryRow is
redundant: the inner branch `Array.isArray(error) ? error : error` always yields
`error`; update the expression in the component (the variables `structured` and
`error` in form_entry_row.tsx, where the prop `error={... as ReactNode}` is set)
to simply choose `structured.message` when present and otherwise `error` (e.g.,
use a single conditional: structured && structured.message !== undefined ?
structured.message : error) and keep the ReactNode cast as before.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/follower_index_default_settings.ts`:
- Around line 16-18: The check `if (!FOLLOWER_INDEX_ADVANCED_SETTINGS[name])`
treats valid falsy defaults (0, false, '') as missing keys; change the existence
check to explicitly test for presence (e.g., use
Object.prototype.hasOwnProperty.call(FOLLOWER_INDEX_ADVANCED_SETTINGS, name) or
(name in FOLLOWER_INDEX_ADVANCED_SETTINGS)) so that functions like
isSettingDefault and areAllSettingsDefault correctly recognize keys whose
defaults are falsy while still throwing for truly unknown setting names.

In
`@x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/utils.ts`:
- Around line 13-17: The defaulting of keyProp to 'id' via "'id' as keyof T" is
unsafe and can produce an "undefined" key; change the function signature to
remove the unsafe default and make keyProp a required parameter (e.g., keyProp:
keyof T) so callers must supply a valid key for T, remove the cast "'id' as
keyof T", and keep the reducer logic but index with item[keyProp] (wrapped with
String(item[keyProp]) to ensure a string key); update all call sites to pass the
correct keyProp.
- Around line 8-9: The generic type T used in objectToArray is unconstrained but
the implementation spreads obj[k], so update the signature to constrain T to
object (e.g., change the generic to T extends object) so TypeScript allows
spreading; keep the parameter type Record<string, T> and the return type Array<T
& { __id__: string }> unchanged—just add the extends object constraint on T in
the objectToArray function declaration.

In
`@x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/reducers/api.ts`:
- Around line 39-47: The reducer is writing to an "undefined" key when
action.payload lacks scope or status; update the handlers for
t.API_REQUEST_START (and the similar handlers for request success/failure) to
guard: only compute and set status like {[String(scope)]: status} when scope is
neither null/undefined and status is defined, otherwise return the previous
state unchanged; locate the switch cases that currently set status (handlers
referencing action.payload, scope, status, error) and add a simple null-check on
scope/status before mutating state to prevent storing undefined keys/values.

In
`@x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/reducers/auto_follow_pattern.ts`:
- Around line 37-47: The function setActiveForIds currently shallow-copies the
byId map but mutates nested objects (shallowCopyByIds[id].active = active),
violating Redux immutability; fix it by creating new objects for each id instead
of mutating the referenced object: iterate ids and for each id assign
shallowCopyByIds[id] = { ...byId[id], active } (or skip/handle missing ids) so
both the map and the individual ParsedAutoFollowPattern objects are new
instances before returning the new Record.

In
`@x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/reducers/stats.ts`:
- Around line 37-40: The reducer handling success(t.AUTO_FOLLOW_STATS_LOAD)
blindly casts action.payload to AutoFollowStats and destructures it, which will
throw if payload is undefined; update the case in the reducer to first guard
that action.payload exists (e.g. if (!action.payload) return state) before
casting/destructuring (payload, recentAutoFollowErrors, rest) so the reducer
safely no-ops when payload is missing and only processes when payload is
present.

---

Nitpick comments:
In
`@x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/form_entry_row.tsx`:
- Around line 143-149: The ternary in the error prop inside FormEntryRow is
redundant: the inner branch `Array.isArray(error) ? error : error` always yields
`error`; update the expression in the component (the variables `structured` and
`error` in form_entry_row.tsx, where the prop `error={... as ReactNode}` is set)
to simply choose `structured.message` when present and otherwise `error` (e.g.,
use a single conditional: structured && structured.message !== undefined ?
structured.message : error) and keep the ReactNode cast as before.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 5ec990c6-0bb0-485d-b620-7c8fe5298817

📥 Commits

Reviewing files that changed from the base of the PR and between 5bf4fe6 and 6936bae.

⛔ Files ignored due to path filters (3)
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/__snapshots__/auto_follow_pattern_form.test.tsx.snap is excluded by !**/*.snap
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/follower_index_form/__snapshots__/follower_index_form.test.tsx.snap is excluded by !**/*.snap
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/__snapshots__/auto_follow_pattern_validators.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (130)
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/auto_follow_pattern_add.test.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/auto_follow_pattern_edit.test.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/auto_follow_pattern_list.test.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/fixtures/auto_follow_pattern.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/fixtures/follower_index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/follower_index_add.test.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/follower_index_edit.test.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/follower_indices_list.test.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/helpers/auto_follow_pattern_add.helpers.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/helpers/auto_follow_pattern_edit.helpers.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/helpers/auto_follow_pattern_list.helpers.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/helpers/constants.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/helpers/follower_index_add.helpers.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/helpers/follower_index_edit.helpers.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/helpers/follower_index_list.helpers.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/helpers/home.helpers.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/helpers/http_requests.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/helpers/http_requests.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/helpers/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/helpers/render.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/helpers/setup_environment.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/home.test.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/app.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/auto_follow_pattern_action_menu/auto_follow_pattern_action_menu.container.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/auto_follow_pattern_action_menu/auto_follow_pattern_action_menu.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/auto_follow_pattern_delete_provider.d.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/auto_follow_pattern_delete_provider.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/auto_follow_pattern_form.test.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/auto_follow_pattern_form.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/auto_follow_pattern_indices_preview.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/auto_follow_pattern_page_title.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/auto_follow_pattern_request_flyout.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/follower_index_actions_providers/follower_index_actions_provider.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/follower_index_actions_providers/follower_index_pause_provider.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/follower_index_actions_providers/follower_index_resume_provider.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/follower_index_actions_providers/follower_index_unfollow_provider.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/follower_index_actions_providers/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/follower_index_form/advanced_settings_fields.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/follower_index_form/follower_index_form.test.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/follower_index_form/follower_index_form.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/follower_index_form/follower_index_request_flyout.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/follower_index_form/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/follower_index_page_title.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/form_entry_row.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/index.d.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/remote_clusters_form_field.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/remote_clusters_provider.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/section_error.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/section_loading.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/section_unauthorized.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/constants/sections.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/auto_follow_pattern_add/auto_follow_pattern_add.container.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/auto_follow_pattern_add/auto_follow_pattern_add.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/auto_follow_pattern_add/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/auto_follow_pattern_edit/auto_follow_pattern_edit.container.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/auto_follow_pattern_edit/auto_follow_pattern_edit.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/auto_follow_pattern_edit/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/follower_index_add/follower_index_add.container.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/follower_index_add/follower_index_add.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/follower_index_add/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/follower_index_edit/follower_index_edit.container.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/follower_index_edit/follower_index_edit.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/follower_index_edit/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/auto_follow_pattern_list.container.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/auto_follow_pattern_list.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/auto_follow_pattern_table/auto_follow_pattern_table.container.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/auto_follow_pattern_table/auto_follow_pattern_table.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/auto_follow_pattern_table/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/detail_panel/detail_panel.container.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/detail_panel/detail_panel.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/detail_panel/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/context_menu/context_menu.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/context_menu/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/detail_panel/detail_panel.container.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/detail_panel/detail_panel.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/follower_indices_table/follower_indices_table.container.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/follower_indices_table/follower_indices_table.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/follower_indices_table/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/follower_indices_list/follower_indices_list.container.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/follower_indices_list/follower_indices_list.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/follower_indices_list/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/home.container.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/home.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/index.d.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/api.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/auto_follow_errors.test.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/auto_follow_errors.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/auto_follow_pattern.test.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/auto_follow_pattern.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/auto_follow_pattern_validators.test.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/auto_follow_pattern_validators.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/follower_index_default_settings.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/follower_index_default_settings.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/get_remote_cluster_name.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/get_remote_cluster_name.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/input_validation.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/notifications.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/routing.d.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/routing.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/track_ui_metric.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/utils.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/utils.test.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/utils.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/action_types.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/actions/api.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/actions/api.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/actions/auto_follow_pattern.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/actions/ccr.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/actions/follower_index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/actions/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/index.d.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/reducers/api.test.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/reducers/api.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/reducers/auto_follow_pattern.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/reducers/auto_follow_pattern.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/reducers/follower_index.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/reducers/follower_index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/reducers/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/reducers/stats.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/reducers/stats.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/selectors/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/store.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/store.ts
💤 Files with no reviewable changes (14)
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/index.d.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/auto_follow_pattern_delete_provider.d.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/get_remote_cluster_name.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/follower_index_default_settings.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/index.d.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/routing.d.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/reducers/stats.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/jest/client_integration/helpers/http_requests.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/index.d.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/reducers/follower_index.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/store.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/actions/api.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/utils.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/reducers/auto_follow_pattern.js

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 1, 2026

@kapral18 Kicking off a full review of the CCR TypeScript migration PR now!


🧠 Learnings used
Learnt from: CR
Repo: elastic/kibana PR: 0
File: x-pack/solutions/observability/plugins/observability_agent_builder/AGENTS.md:0-0
Timestamp: 2026-03-06T09:23:07.998Z
Learning: Applies to x-pack/solutions/observability/plugins/observability_agent_builder/server/tools/**/*.{ts,tsx,js} : Follow tool design principles, ECS/OTel compatibility, APM data types, parameter conventions, testing workflows, and pre-merge checklist for Observability tools as documented in server/tools/AGENTS.md

Learnt from: CR
Repo: elastic/kibana PR: 0
File: x-pack/solutions/observability/plugins/observability_agent_builder/AGENTS.md:0-0
Timestamp: 2026-03-18T14:14:05.681Z
Learning: Applies to x-pack/solutions/observability/plugins/observability_agent_builder/server/**/*.{ts,tsx,js} : Follow design principles, ECS/OTel compatibility, APM data types, parameter conventions, and testing workflows as documented in the Development Guide

Learnt from: CR
Repo: elastic/kibana PR: 0
File: x-pack/solutions/observability/plugins/observability_agent_builder/server/AGENTS.md:0-0
Timestamp: 2026-03-18T14:14:27.801Z
Learning: Applies to x-pack/solutions/observability/plugins/observability_agent_builder/server/x-pack/solutions/observability/test/api_integration_deployment_agnostic/apis/observability_agent_builder/tools/**/*.ts : Create API integration tests for new tools covering filters, groupBy dimensions, and edge cases in `x-pack/solutions/observability/test/api_integration_deployment_agnostic/apis/observability_agent_builder/tools/`.

Learnt from: CR
Repo: elastic/kibana PR: 0
File: x-pack/solutions/observability/plugins/observability_agent_builder/AGENTS.md:0-0
Timestamp: 2026-03-06T03:54:46.342Z
Learning: Applies to x-pack/solutions/observability/plugins/observability_agent_builder/x-pack/solutions/observability/test/api_integration_deployment_agnostic/apis/observability_agent_builder/**/*.{ts,tsx,js} : Follow API integration test structure guidelines and use shared utilities as documented in x-pack/solutions/observability/test/api_integration_deployment_agnostic/apis/observability_agent_builder/AGENTS.md

Learnt from: CR
Repo: elastic/kibana PR: 0
File: x-pack/solutions/observability/plugins/observability_agent_builder/AGENTS.md:0-0
Timestamp: 2026-03-06T10:48:39.498Z
Learning: Applies to x-pack/solutions/observability/plugins/observability_agent_builder/src/platform/packages/shared/kbn-synthtrace/src/scenarios/agent_builder/**/*.{ts,tsx,js} : Generate synthetic test data for tools and AI Insights using Synthtrace scenarios as documented in src/platform/packages/shared/kbn-synthtrace/src/scenarios/agent_builder/AGENTS.md

Learnt from: CR
Repo: elastic/kibana PR: 0
File: x-pack/solutions/observability/plugins/observability_agent_builder/server/AGENTS.md:0-0
Timestamp: 2026-03-18T14:14:27.801Z
Learning: Applies to x-pack/solutions/observability/plugins/observability_agent_builder/server/src/platform/packages/shared/kbn-synthtrace/src/scenarios/agent_builder/tools/**/*.ts : Create Synthtrace scenarios for test data generation in `src/platform/packages/shared/kbn-synthtrace/src/scenarios/agent_builder/tools/`.

Learnt from: CR
Repo: elastic/kibana PR: 0
File: x-pack/solutions/observability/plugins/observability_agent_builder/AGENTS.md:0-0
Timestamp: 2026-03-06T12:00:53.329Z
Learning: Applies to x-pack/solutions/observability/plugins/observability_agent_builder/server/routes/ai_insights/**/*.{ts,tsx,js} : Follow AI Insights architecture guidelines including prefetched context, hardcoded prompts, prompt design, UI integration, conversation handoff, and testing as documented in server/routes/ai_insights/AGENTS.md

Learnt from: CR
Repo: elastic/kibana PR: 0
File: x-pack/solutions/observability/plugins/observability_agent_builder/AGENTS.md:0-0
Timestamp: 2026-03-18T14:14:05.681Z
Learning: Applies to x-pack/solutions/observability/plugins/observability_agent_builder/server/routes/ai_insights/**/*.{ts,tsx,js} : Design AI Insights with prefetched context and hardcoded prompts, ensure proper prompt design, UI integration, conversation handoff, and test thoroughly

Learnt from: CR
Repo: elastic/kibana PR: 0
File: x-pack/solutions/observability/plugins/observability_agent_builder/AGENTS.md:0-0
Timestamp: 2026-03-18T14:14:05.681Z
Learning: Applies to x-pack/solutions/observability/plugins/observability_agent_builder/x-pack/solutions/observability/test/api_integration_deployment_agnostic/apis/observability_agent_builder/**/*.{ts,tsx,js} : Structure API integration tests following the guidelines in the API Integration Tests guide, using shared utilities and following test structure conventions

Learnt from: CR
Repo: elastic/kibana PR: 0
File: x-pack/solutions/observability/plugins/observability_agent_builder/AGENTS.md:0-0
Timestamp: 2026-03-18T14:14:05.681Z
Learning: Applies to x-pack/solutions/observability/plugins/observability_agent_builder/src/platform/packages/shared/kbn-synthtrace/src/scenarios/agent_builder/**/*.{ts,tsx,js} : Generate synthetic test data using Synthtrace scenarios following the Agent Builder patterns
✅ Actions performed

Full review triggered.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 1, 2026

📝 Walkthrough

Walkthrough

This pull request converts the Cross-Cluster Replication (CCR) plugin from JavaScript to TypeScript across all layers. Changes include migrating test files with new type annotations, converting helper modules to TypeScript with explicit return/parameter types, replacing PropTypes with TypeScript interfaces in React components, adding typed Redux actions and reducers, and converting service utilities with proper type definitions. Old .js files are removed and replaced with .ts/.tsx equivalents. Type-only declaration files (.d.ts) are removed where implementations now exist. The overall refactor introduces strict typing for React props, Redux state/actions, API responses, and utility function signatures while preserving existing functionality.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • 🛠️ Update Documentation: Commit on current branch
  • 🛠️ Update Documentation: Create PR

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/follower_index_edit/follower_index_edit.tsx (1)

148-175: ⚠️ Potential issue | 🟠 Major

Rendering an object as ReactNode will display [object Object].

When statusCode === 404, errorMessage becomes { error: "..." } (lines 150-158), but it's then cast and rendered directly in the <p> tag at line 175. This will display [object Object] instead of the intended message.

Proposed fix
-        body={<p>{errorMessage as unknown as ReactNode}</p>}
+        body={<p>{typeof errorMessage === 'object' && errorMessage !== null && 'error' in errorMessage ? (errorMessage as { error: ReactNode }).error : (errorMessage as unknown as ReactNode)}</p>}

Or restructure the error handling to always produce a ReactNode:

     const errorMessage =
       error.body.statusCode === 404
-        ? {
-            error: i18n.translate(
+        ? i18n.translate(
               'xpack.crossClusterReplication.followerIndexEditForm.loadingErrorMessage',
               {
                 defaultMessage: `The follower index ''{name}'' does not exist.`,
                 values: { name },
               }
-            ),
-          }
+            )
         : error;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/follower_index_edit/follower_index_edit.tsx`
around lines 148 - 175, The code is rendering an object as a ReactNode: when
error.body.statusCode === 404 the variable errorMessage is set to { error: "..."
} and then cast and rendered in the <p> causing “[object Object]”. Fix by making
errorMessage a string or ReactNode instead of an object (update the conditional
that assigns errorMessage in follower_index_edit.tsx to return the
i18n.translate(...) string for the 404 branch and for the non-404 branch return
a meaningful string like error.message or String(error)), and then render that
string (or a proper React element) in the body prop instead of casting the
object.
x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/auto_follow_pattern_edit/auto_follow_pattern_edit.tsx (1)

104-131: ⚠️ Potential issue | 🟠 Major

Rendering error object directly will display "[object Object]"

When error.body.statusCode !== 404, errorMessage is assigned the raw error object. Casting it to ReactNode and rendering it will produce garbage output in the UI.

Proposed fix
     const errorMessage =
       error.body.statusCode === 404
         ? {
             error: i18n.translate(
               'xpack.crossClusterReplication.autoFollowPatternEditForm.loadingErrorMessage',
               {
                 defaultMessage: `The auto-follow pattern ''{name}'' does not exist.`,
                 values: { name },
               }
             ),
           }
         : error;
 
     const listNav = reactRouterNavigate(this.props.history, `/auto_follow_patterns`);
 
     return (
       <EuiPageTemplate.EmptyPrompt
         color="danger"
         iconType="warning"
         title={...}
-        body={<p>{errorMessage as unknown as ReactNode}</p>}
+        body={
+          <p>
+            {error.body.statusCode === 404
+              ? (errorMessage as { error: string }).error
+              : i18n.translate(
+                  'xpack.crossClusterReplication.autoFollowPatternEditForm.loadingErrorGeneric',
+                  { defaultMessage: 'An error occurred while loading the auto-follow pattern.' }
+                )}
+          </p>
+        }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/auto_follow_pattern_edit/auto_follow_pattern_edit.tsx`
around lines 104 - 131, The code assigns the raw error object to errorMessage
when error.body.statusCode !== 404 and then renders it (casting to ReactNode),
which yields “[object Object]”; update the error handling in the component so
errorMessage is a string or React element (e.g., use error.message, combine
statusCode and message, or JSON.stringify(error) into a readable string) instead
of the raw object; modify the branch that sets errorMessage (the variable
referencing error.body.statusCode and error) so the non-404 path produces a
user-friendly string/JSX and keep rendering the result inside the
<EuiPageTemplate.EmptyPrompt> body as before.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/utils.ts`:
- Around line 11-17: The defaulting of keyProp to the casted 'id' in
arrayToObject is unsafe because when T does not include an 'id' property
multiple items become acc['undefined']; fix by removing the unsafe default and
require an explicit key property: change the signature of arrayToObject to
accept a keyProp parameter (e.g., keyProp: keyof T or generic K extends keyof T)
without a default, or constrain the generic so T must include an id (if that is
intended); update callers to pass the correct keyProp when calling arrayToObject
and adjust usages of arrayToObject to supply the explicit key to avoid silent
collisions on 'undefined'.

In
`@x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/reducers/auto_follow_pattern.ts`:
- Around line 37-46: setActiveForIds currently shallow-copies the map but
mutates the nested entity objects and will throw if an id is missing; update
setActiveForIds to be fully immutable and missing-id safe by creating a new
result object, iterating ids, checking if byId[id] exists, and for each existing
entry assign a new object copy of the entity with active set to the provided
value (leaving non-existent ids ignored), then return the new map so neither
original map nor original entity objects are mutated.

---

Outside diff comments:
In
`@x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/auto_follow_pattern_edit/auto_follow_pattern_edit.tsx`:
- Around line 104-131: The code assigns the raw error object to errorMessage
when error.body.statusCode !== 404 and then renders it (casting to ReactNode),
which yields “[object Object]”; update the error handling in the component so
errorMessage is a string or React element (e.g., use error.message, combine
statusCode and message, or JSON.stringify(error) into a readable string) instead
of the raw object; modify the branch that sets errorMessage (the variable
referencing error.body.statusCode and error) so the non-404 path produces a
user-friendly string/JSX and keep rendering the result inside the
<EuiPageTemplate.EmptyPrompt> body as before.

In
`@x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/follower_index_edit/follower_index_edit.tsx`:
- Around line 148-175: The code is rendering an object as a ReactNode: when
error.body.statusCode === 404 the variable errorMessage is set to { error: "..."
} and then cast and rendered in the <p> causing “[object Object]”. Fix by making
errorMessage a string or ReactNode instead of an object (update the conditional
that assigns errorMessage in follower_index_edit.tsx to return the
i18n.translate(...) string for the 404 branch and for the non-404 branch return
a meaningful string like error.message or String(error)), and then render that
string (or a proper React element) in the body prop instead of casting the
object.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: a8af1186-ded4-4436-b947-c91e28fe02ab

📥 Commits

Reviewing files that changed from the base of the PR and between 5bf4fe6 and 6936bae.

⛔ Files ignored due to path filters (3)
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/__snapshots__/auto_follow_pattern_form.test.tsx.snap is excluded by !**/*.snap
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/follower_index_form/__snapshots__/follower_index_form.test.tsx.snap is excluded by !**/*.snap
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/__snapshots__/auto_follow_pattern_validators.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (130)
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/auto_follow_pattern_add.test.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/auto_follow_pattern_edit.test.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/auto_follow_pattern_list.test.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/fixtures/auto_follow_pattern.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/fixtures/follower_index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/follower_index_add.test.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/follower_index_edit.test.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/follower_indices_list.test.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/helpers/auto_follow_pattern_add.helpers.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/helpers/auto_follow_pattern_edit.helpers.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/helpers/auto_follow_pattern_list.helpers.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/helpers/constants.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/helpers/follower_index_add.helpers.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/helpers/follower_index_edit.helpers.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/helpers/follower_index_list.helpers.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/helpers/home.helpers.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/helpers/http_requests.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/helpers/http_requests.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/helpers/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/helpers/render.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/helpers/setup_environment.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/__jest__/client_integration/home.test.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/app.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/auto_follow_pattern_action_menu/auto_follow_pattern_action_menu.container.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/auto_follow_pattern_action_menu/auto_follow_pattern_action_menu.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/auto_follow_pattern_delete_provider.d.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/auto_follow_pattern_delete_provider.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/auto_follow_pattern_form.test.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/auto_follow_pattern_form.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/auto_follow_pattern_indices_preview.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/auto_follow_pattern_page_title.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/auto_follow_pattern_request_flyout.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/follower_index_actions_providers/follower_index_actions_provider.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/follower_index_actions_providers/follower_index_pause_provider.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/follower_index_actions_providers/follower_index_resume_provider.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/follower_index_actions_providers/follower_index_unfollow_provider.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/follower_index_actions_providers/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/follower_index_form/advanced_settings_fields.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/follower_index_form/follower_index_form.test.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/follower_index_form/follower_index_form.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/follower_index_form/follower_index_request_flyout.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/follower_index_form/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/follower_index_page_title.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/form_entry_row.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/index.d.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/remote_clusters_form_field.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/remote_clusters_provider.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/section_error.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/section_loading.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/section_unauthorized.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/constants/sections.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/auto_follow_pattern_add/auto_follow_pattern_add.container.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/auto_follow_pattern_add/auto_follow_pattern_add.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/auto_follow_pattern_add/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/auto_follow_pattern_edit/auto_follow_pattern_edit.container.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/auto_follow_pattern_edit/auto_follow_pattern_edit.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/auto_follow_pattern_edit/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/follower_index_add/follower_index_add.container.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/follower_index_add/follower_index_add.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/follower_index_add/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/follower_index_edit/follower_index_edit.container.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/follower_index_edit/follower_index_edit.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/follower_index_edit/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/auto_follow_pattern_list.container.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/auto_follow_pattern_list.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/auto_follow_pattern_table/auto_follow_pattern_table.container.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/auto_follow_pattern_table/auto_follow_pattern_table.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/auto_follow_pattern_table/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/detail_panel/detail_panel.container.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/detail_panel/detail_panel.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/detail_panel/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/context_menu/context_menu.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/context_menu/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/detail_panel/detail_panel.container.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/detail_panel/detail_panel.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/follower_indices_table/follower_indices_table.container.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/follower_indices_table/follower_indices_table.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/follower_indices_table/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/follower_indices_list/follower_indices_list.container.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/follower_indices_list/follower_indices_list.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/follower_indices_list/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/home.container.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/home.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/home/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/index.d.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/api.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/auto_follow_errors.test.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/auto_follow_errors.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/auto_follow_pattern.test.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/auto_follow_pattern.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/auto_follow_pattern_validators.test.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/auto_follow_pattern_validators.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/follower_index_default_settings.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/follower_index_default_settings.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/get_remote_cluster_name.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/get_remote_cluster_name.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/input_validation.tsx
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/notifications.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/routing.d.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/routing.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/track_ui_metric.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/utils.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/utils.test.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/utils.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/action_types.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/actions/api.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/actions/api.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/actions/auto_follow_pattern.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/actions/ccr.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/actions/follower_index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/actions/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/index.d.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/reducers/api.test.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/reducers/api.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/reducers/auto_follow_pattern.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/reducers/auto_follow_pattern.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/reducers/follower_index.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/reducers/follower_index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/reducers/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/reducers/stats.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/reducers/stats.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/selectors/index.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/store.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/store.ts
💤 Files with no reviewable changes (14)
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/index.d.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/jest/client_integration/helpers/http_requests.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/components/auto_follow_pattern_delete_provider.d.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/sections/index.d.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/reducers/auto_follow_pattern.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/index.d.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/get_remote_cluster_name.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/routing.d.ts
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/reducers/follower_index.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/reducers/stats.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/store.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/follower_index_default_settings.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/services/utils.js
  • x-pack/platform/plugins/private/cross_cluster_replication/public/app/store/actions/api.js

@kapral18 kapral18 force-pushed the chore/ccr/migrate-to-ts-239613 branch 5 times, most recently from 777d635 to cc617f4 Compare April 8, 2026 01:15
@kapral18 kapral18 force-pushed the chore/ccr/migrate-to-ts-239613 branch 4 times, most recently from bd057aa to 2ce707f Compare April 10, 2026 19:47

export type CcrApiError = Error | IHttpFetchError<ResponseErrorBody>;

export const toCcrApiError = (error: unknown): CcrApiError => {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For reviewers: we normalize unknown thrown values into a real Error (toCcrApiError) and then narrow fetch errors via isHttpFetchError so UI code can safely read response.status / body.statusCode and body.message. This avoids leaking non-Error objects into rendering (previously could trigger "Objects are not valid as a React child") and makes error display consistent across CCR.

if (isUsingAdvancedSettings) {
uiMetrics.push(UIM_FOLLOWER_INDEX_USE_ADVANCED_OPTIONS);
}
const { status: _status, shards: _shards, ...body } = followerIndex as FollowerIndex;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For reviewers: createFollowerIndex intentionally strips status/shards from the POST payload. Those are response-only fields on FollowerIndex, and the server route schema rejects them (we reproduced a runtime failure: "Additional properties are not allowed ('status' was unexpected)"). This keeps the request aligned with the route contract and fixes follower-index creation.

// Expect an error in the shape provided by Angular's $http service.
if (error && error.body) {
} catch (error: unknown) {
const apiError = toCcrApiError(error);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For reviewers: permission-check error handling now prefers ResponseErrorBody.message when present (falls back to Error.message), using the shared CCR error helpers. This slightly changes the displayed text in some failure modes (more precise server message) while keeping fatal-errors for non-HTTP exceptions.

@kapral18 kapral18 marked this pull request as ready for review April 10, 2026 20:10
@kapral18 kapral18 requested a review from a team as a code owner April 10, 2026 20:10
@elasticmachine
Copy link
Copy Markdown
Contributor

Pinging @elastic/kibana-management (Team:Kibana Management)

kapral18 added 14 commits April 19, 2026 20:17
Both branches of the previous ternary returned `error.message`, so collapse
it to a single expression.

Made-with: Cursor
Pass the accumulator type to `reduce` so the seed `{}` no longer needs an
`as Record<string, T>` cast.

Made-with: Cursor
`defaultProps` was carried over from the previous test helper but no
caller passes it, so remove the option and the corresponding spread.

Made-with: Cursor
A short JSDoc comment so the next reader does not have to infer the
intent from the `value === undefined ||` short-circuit.

Made-with: Cursor
The local `RemoteCluster` interface was duplicating fields already
exported as `RemoteClusterRow` from `services/api`. Import and use that
type instead so the shape stays in sync with the API.

Made-with: Cursor
All call sites already pass `title`, so the prop is required. Removing
the optional marker also removes the non-null assertion in JSX, so the
component cannot crash on a missing title element.

Made-with: Cursor
`FollowerIndexEdit` already destructures `shards` out of the data it
hands to the form, so narrow `FollowerIndexForm.followerIndex` to
`Omit<FollowerIndex, 'shards'>` and remove the matching `as
FollowerIndex` cast at the call site. The form's own `shards`
destructuring becomes dead and is removed.

Made-with: Cursor
Annotate `getTableColumns` and `search` with the matching
`EuiInMemoryTableProps<ParsedAutoFollowPattern>` slices, set `type:
'icon'` on each row action so EUI can pick the icon-action variant, and
type `onSearch` with `EuiSearchBarOnChangeArgs`. With those in place the
`as` casts at the `<EuiInMemoryTable>` site are unnecessary.

Made-with: Cursor
Annotate `getTableColumns`, the row `actions` array, and `search` with
the matching `EuiInMemoryTableProps<FollowerIndexWithPausedStatus>`
slices, set `type: 'icon'` on each row action, type `onSearch` with
`EuiSearchBarOnChangeArgs`, and coerce `item.isPaused` to a boolean for
the `available` predicate. This removes the `as` casts at the
`<EuiInMemoryTable>` site.

Made-with: Cursor
Move the null-check-and-throw out of every consumer and into a single
`reactRouterOrThrow` getter on the routing service, switch the backing
field to a JS private field (`#reactRouter`) so it cannot be reached
from outside the class, and update consumers (forms, tables, detail
panels, resume provider, routing test mock) to read through the new
getter or the existing `reactRouter` accessor instead of the underscore
prefixed field.

Made-with: Cursor
Make `arrify` and `removeEmptyFields` generic so callers no longer need
`as T[]` casts at the use site, and remove the unused `wait` helper.
The pause/resume/unfollow follower-index providers drop their now
redundant `arrify(...) as ...` casts.

Made-with: Cursor
Pass dispatch/own prop generics to `connect` and split the dispatch prop
shape into a named `DispatchProps` type so the wrapper inherits its
public surface from the typed connect call instead of an
`as ComponentType<OwnProps>` cast.

Made-with: Cursor
…signment

`_toasts` and `_fatalErrors` are only set by `init()`; lying to the
type system with a definite-assignment assertion lets callers fail with
a confusing "cannot read properties of undefined" later. Mark them
explicitly optional and throw a descriptive error from `getToasts` /
`getFatalErrors` if they are read before `init()` ran.

Made-with: Cursor
Switch `FormEntryRow.onValueUpdate` to receive the parsed scalar value
and let each call site decide which field key to write. This drops the
unsafe `as Partial<FollowerIndexFormFields>` casts in
`FollowerIndexForm` and lets the caller fan into either `name`,
`leaderIndex`, or one of the advanced settings without rebuilding an
intermediate object. While here, extract `StructuredError` and an
`isStructuredError` type guard, widen `value` to `string | number |
undefined` to match the underlying inputs, replace the form's
`reduce`-with-cast in `getFieldsErrors` with a typed `for..of`, and
drop the redundant `status`/`shards` stripping that the form's own
field whitelist already covers.

Made-with: Cursor
@elasticmachine
Copy link
Copy Markdown
Contributor

elasticmachine commented Apr 19, 2026

💔 Build Failed

Failed CI Steps

Test Failures

  • [job] [logs] FTR Configs #53 / Entity Analytics - Risk Score Maintainer @ess @serverless @serverlessQA Risk Score Maintainer Task Lifecycle with maintainer test logs data @skipInServerlessMKI resumes producing additional scores after stop and restart when triggered
  • [job] [logs] FTR Configs #53 / Entity Analytics - Risk Score Maintainer @ess @serverless @serverlessQA Risk Score Maintainer Task Lifecycle with maintainer test logs data @skipInServerlessMKI resumes producing additional scores after stop and restart when triggered

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
crossClusterReplication 112 113 +1

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
crossClusterReplication 139.6KB 144.4KB +4.7KB

Page load bundle

Size of the bundles that are downloaded on every page load. Target size is below 100kb

id before after diff
crossClusterReplication 11.6KB 11.8KB +250.0B
Unknown metric groups

ESLint disabled line counts

id before after diff
crossClusterReplication 9 0 -9

Total ESLint disabled count

id before after diff
crossClusterReplication 9 0 -9

History

The ES client typings for `CcrResumeFollowRequest` move the advanced
settings (`max_outstanding_*`, `max_read_request_*`, etc.) to top-level
parameters and disallow them inside `body`. Spread the serialized
settings directly into the request and update the matching jest
expectation. The HTTP wire format is unchanged.

Made-with: Cursor
* main: (114 commits)
  Fix observability_ai_assistant_tool_call EBT error when connector is an inference endpoint (elastic#263334)
  init on install (elastic#263732)
  [One Workflow] fail-fast TaskRecovery for interrupted runs (elastic#261275)
  [Entity Store] Reset state error after successful task run (elastic#263087)
  [api-docs] 2026-04-19 Daily api_docs build (elastic#264280)
  [UII] Fix integration card row height calculation (elastic#264212)
  [scout] migrate FTR logstash api tests (elastic#262953)
  [StorageIndexAdapter] Set auto_expand_replicas to fix yellow health on single-node ES clusters (elastic#263096)
  [api-docs] 2026-04-18 Daily api_docs build (elastic#264260)
  [Scout] Update test config manifests (elastic#264257)
  [Security Solution][Detection Engine] enables AI rule creation feature flag (elastic#264036)
  [dashboards as code] only validate id on PUT route when creating new dashboard (elastic#264161)
  chore(NA): bump version to 9.5.0 (elastic#262165)
  skip failing test suite (elastic#263649)
  skip failing test suite (elastic#264236)
  [Discover] Convert remaining Enzyme tests to RTL (elastic#259676)
  auto-implement: Labels in model endpoints table of the model details flyout look misaligned (elastic#263770)
  [ci] Promote ES docker image after verification (elastic#263890)
  [Observability:Onboarding] Remove suppress global announcements that was breaking ensemble tests (elastic#264169)
  [Cases][AttachmentV2] Migrate persistable state part 2 - ML and AIOps charts (elastic#262597)
  ...
@kapral18 kapral18 force-pushed the chore/ccr/migrate-to-ts-239613 branch from ff94f62 to e131578 Compare April 19, 2026 20:18
@kapral18
Copy link
Copy Markdown
Contributor Author

@SoniaSanzV @damian-polewski — your review surfaced a handful of recurring sharp edges from the migration (extra as casts, definite assignment, inferred props, payload-shape mismatches). After working through your threads I went back over the diff with the same lens and found more in the same vein.

These are five small, targeted commits — each touches 1-2 files, largest is ~80 lines net, no architectural changes or new scope. Kept separate from the comment-driven ones so you can skim them quickly:

  • 6aeebd9 — extension of the arrayToObject thread: arrify and removeEmptyFields retyped as generics so callers stop needing as casts. Also drops the unused wait helper.
  • 804fb3f — extension of the EUI table typing threads: AutoFollowPatternActionMenu container uses explicit connect<DispatchProps, OwnProps> so the dispatch prop shape is spelled out instead of inferred.
  • ed40c97 — same family as the title! thread: CCR notifications service drops _toasts!/_fatalErrors! definite assignment in favor of runtime checks that throw on access before init(). Init-order bugs now surface at the call site instead of as cannot read 'add' of undefined.
  • a7982c1 — same theme as the shards/as FollowerIndex thread: FormEntryRow.onValueUpdate now emits a scalar string | number instead of an object, which lets every call site drop its as Partial<FollowerIndexFormFields> cast without changing runtime behavior.
  • 3a10872 — not flagged by anyone, caught while tracing the wire format end-to-end after the auto-follow save split: register_update_route spreads resumeParams directly into ccr.resumeFollow top-level params instead of nesting under body. Matches the ES client CcrResumeFollowRequest shape (advanced settings are top-level params, not body fields). Existing route Jest test updated.

Thanks again for the thorough review — it caught patterns I'd missed and gave me the lens for these follow-ups.

Copy link
Copy Markdown
Contributor

@SoniaSanzV SoniaSanzV left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you for addressing the feedback and the other improvements! LGTM!

Copy link
Copy Markdown
Contributor

@damian-polewski damian-polewski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @kapral18 for addressing all the issues and adding improvements! LGTM and great job!

@kibanamachine
Copy link
Copy Markdown
Contributor

💚 Build Succeeded

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
crossClusterReplication 112 113 +1

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
crossClusterReplication 139.6KB 144.4KB +4.7KB

Page load bundle

Size of the bundles that are downloaded on every page load. Target size is below 100kb

id before after diff
crossClusterReplication 11.6KB 11.8KB +250.0B
Unknown metric groups

ESLint disabled line counts

id before after diff
crossClusterReplication 9 0 -9

Total ESLint disabled count

id before after diff
crossClusterReplication 9 0 -9

@kapral18 kapral18 merged commit 9bd5122 into elastic:main Apr 27, 2026
17 checks passed
@kapral18 kapral18 deleted the chore/ccr/migrate-to-ts-239613 branch April 27, 2026 19:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:skip This PR does not require backporting release_note:skip Skip the PR/issue when compiling release notes Team:Kibana Management Dev Tools, Index Management, Upgrade Assistant, ILM, Ingest Node Pipelines, and more t// technical debt Improvement of the software architecture and operational architecture v9.4.0 v9.5.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[CCR] Migrate JS code to TS

5 participants